#include "StdAfx.h"
#include "ClientsManager.h"
#include <Psapi.h>
#include <iostream>
#include <ctime>
#include "Settings.h"
using namespace std;

static DWORD WINAPI WatchDog(LPVOID lpParameter) {
	ClientsManager* manager = (ClientsManager*) lpParameter;
	if (manager == NULL) {
		return 0;
	}
	while (1) {
		time_t now = time(NULL);
		if (manager->m_lastCallTime != 0 && now - manager->m_lastCallTime
				> Settings::getMaxProseccNumber()) {
			//cout<<"time out, kill processes"<<endl;
			system("taskkill /f /im skypeMultiStart.exe");
			system("taskkill /f /im skype.exe");
			system("taskkill /f /im skypePM.exe");
			//cout<<"end of killing process"<<endl;
		}
		Sleep(10000);
	}
	return 0;
}

ClientsManager::ClientsManager(void) :
	m_apiCtrl(this), m_isRun(true), m_lastCallTime(0) {
	InitializeCriticalSection(&m_clientsCriticalSection);
	m_apiCtrl.StartMessageLoop();
	m_watchDogThread = CreateThread(NULL, 0, WatchDog, NULL, 0, NULL);
}

ClientsManager::~ClientsManager(void) {
	if (m_watchDogThread != 0) {
		TerminateThread(m_watchDogThread, 0);
	}
	DeleteCriticalSection(&m_clientsCriticalSection);
}

string ClientsManager::procName(DWORD processID) {
	TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");

	// Get a handle to the process.

	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
			FALSE, processID);

	// Get the process name.

	if (NULL != hProcess) {
		HMODULE hMod;
		DWORD cbNeeded;

		if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
			GetModuleBaseName(hProcess, hMod, szProcessName,
					sizeof(szProcessName) / sizeof(TCHAR));
		}
	}

	// Print the process name and identifier.

	wstring wprocessName = szProcessName;
	string processName(wprocessName.begin(), wprocessName.end());

	CloseHandle(hProcess);

	return processName;
}

void ClientsManager::scanClients() {
	// Get the list of process identifiers.

	DWORD aProcesses[1024], cbNeeded, cProcesses;
	unsigned int i;

	if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
		return;

	// Calculate how many process identifiers were returned.

	cProcesses = cbNeeded / sizeof(DWORD);

	// Print the name and process identifier for each process.

	map<DWORD, SkypeClient*> newClients, oldClients;
	EnterCriticalSection(&m_clientsCriticalSection);
	//// remove closed process.
	//for (map<DWORD, SkypeClient*>::iterator it = m_clients.begin(); it!=m_clients.end(); it++)
	//{
	//	if(it->second->state() == SkypeClient::STATE_CLOSED)
	//	{
	//		delete it->second;
	//	}
	//}

	for (i = 0; i < cProcesses; i++) {
		if (aProcesses[i] != 0) {
			string processName = procName(aProcesses[i]);
			//cout<<processName<<endl;
			if (processName == "Skype.exe") {
				map<DWORD, SkypeClient*>::iterator itFind = m_clients.find(
						aProcesses[i]);
				if (itFind != m_clients.end()) {
					// find a existed skype process
					oldClients[aProcesses[i]] = itFind->second;
					m_clients.erase(itFind);
				} else {
					// new skype process
					SkypeClient* client;
					client = new SkypeClient(this);
					client->procId() = aProcesses[i];
					newClients[aProcesses[i]] = client;
				}
			}
		}
	}
	// infirm closed processed.
	for (map<DWORD, SkypeClient*>::iterator it = m_clients.begin(); it
			!= m_clients.end(); it++) {
		it->second->processClosed();
	}
	m_clients.clear();
	m_clients.insert(newClients.begin(), newClients.end());
	m_clients.insert(oldClients.begin(), oldClients.end());
	LeaveCriticalSection(&m_clientsCriticalSection);

}

void ClientsManager::listClients() {
	cout << "List of skype processed:" << endl;
	cout << "\tPID\tUIWIN\t\tCTRLWIN\t\tTIMECNT" << endl;
	EnterCriticalSection(&m_clientsCriticalSection);
	for (map<DWORD, SkypeClient*>::const_iterator it = m_clients.begin(); it
			!= m_clients.end(); it++) {
		unsigned int id = it->second->procId();
		void* uiWin = it->second->uiWin();
		void* ctrlWin = it->second->ctrlWin();
		int t = it->second->timeCount();
		cout << "\t" << id << "\t" << uiWin << "\t" << ctrlWin << "\t" << t
				<< endl;
	}
	LeaveCriticalSection(&m_clientsCriticalSection);
}
SkypeClient* ClientsManager::findClientbyWin(HWND win) {
	DWORD pid, threadId;
	threadId = GetWindowThreadProcessId((HWND) win, &pid);
	EnterCriticalSection(&m_clientsCriticalSection);
	map<DWORD, SkypeClient*>::iterator it = m_clients.find(pid);
	SkypeClient* ret = NULL;
	if (it != m_clients.end()) {
		ret = it->second;
	}
	LeaveCriticalSection(&m_clientsCriticalSection);
	return ret;

}
//////////////////////////////////////////////////////////////////////////
void ClientsManager::run() {
	bool clientsEmpty = true;
	while (m_isRun || !clientsEmpty) {
		scanClients();
		EnterCriticalSection(&m_clientsCriticalSection);
		clientsEmpty = m_clients.empty();
		LeaveCriticalSection(&m_clientsCriticalSection);
		if (!clientsEmpty) {
			m_apiCtrl.scanCtrlWin();
		}
		listClients();
		Sleep(5000);
	}
}

void ClientsManager::stop() {
	m_isRun = false;
	EnterCriticalSection(&m_clientsCriticalSection);
	for (map<DWORD, SkypeClient*>::iterator it = m_clients.begin(); it
			!= m_clients.end(); it++) {
		it->second->stop();
	}
	LeaveCriticalSection(&m_clientsCriticalSection);
}
//////////////////////////////////////////////////////////////////////////								client events
void ClientsManager::clientLogined(const SkypeClient* client) {
	for (set<ClientsManagerObserver*>::iterator it = m_observers.begin(); it
			!= m_observers.end(); it++) {
		(*it)->clientLogined(client);
	}
}
void ClientsManager::clientOnline(const SkypeClient* client) {
	for (set<ClientsManagerObserver*>::iterator it = m_observers.begin(); it
			!= m_observers.end(); it++) {
		(*it)->clientOnline(client);
	}
}
void ClientsManager::clientTimeOut(const SkypeClient* client) {
	for (set<ClientsManagerObserver*>::iterator it = m_observers.begin(); it
			!= m_observers.end(); it++) {
		(*it)->clientTimeOut(client);
	}
}
void ClientsManager::clientCallRefused(const SkypeClient* client) {
	for (set<ClientsManagerObserver*>::iterator it = m_observers.begin(); it
			!= m_observers.end(); it++) {
		(*it)->clientCallRefused(client);
	}
}
void ClientsManager::clientCallFailed(const SkypeClient* client) {
	for (set<ClientsManagerObserver*>::iterator it = m_observers.begin(); it
			!= m_observers.end(); it++) {
		(*it)->clientCallFailed(client);
	}
}
void ClientsManager::clientCallBusy(const SkypeClient* client) {
	for (set<ClientsManagerObserver*>::iterator it = m_observers.begin(); it
			!= m_observers.end(); it++) {
		(*it)->clientCallBusy(client);
	}
}
void ClientsManager::clientCallFinished(const SkypeClient* client) {
	for (set<ClientsManagerObserver*>::iterator it = m_observers.begin(); it
			!= m_observers.end(); it++) {
		(*it)->clientCallFinished(client);
	}
}
void ClientsManager::clientCallMissed(const SkypeClient* client) {
	for (set<ClientsManagerObserver*>::iterator it = m_observers.begin(); it
			!= m_observers.end(); it++) {
		(*it)->clientCallMissed(client);
	}
}
//////////////////////////////////////////////////////////////////////////					observers
void ClientsManager::addObserver(ClientsManagerObserver* observer) {
	m_observers.insert(observer);
}
void ClientsManager::removeObserver(ClientsManagerObserver* observer) {
	m_observers.erase(observer);
}
//////////////////////////////////////////////////////////////////////////					client manage
SkypeClient* ClientsManager::makeCall(const string& callerId,
		const string& callerPwd, const string& calleeId) {
	EnterCriticalSection(&m_clientsCriticalSection);
	map<DWORD, SkypeClient*>::iterator it = m_clients.begin();
	SkypeClient* client = NULL;
	while (it != m_clients.end()) {
		if (it->second && it->second->available()) {
			it->second->setUser(callerId, callerPwd);
			it->second->setCallee(calleeId);
			it->second->call();
			client = it->second;
			m_lastCallTime = time(NULL);
			break;
		}
		it++;
	}
	bool startSkype = false;
	if (it == m_clients.end() && m_clients.size() < Settings::getMaxProseccNumber()) {
		startSkype = true;
	}
	LeaveCriticalSection(&m_clientsCriticalSection);
	if (startSkype) {
		//cout<<"starting skype"<<endl;
		system("skypeMultiStart.exe");
		//cout<<"end starting skype"<<endl;
		Sleep(3000);
	}
	scanClients();

	EnterCriticalSection(&m_clientsCriticalSection);
	bool clientsEmpty = m_clients.empty();
	LeaveCriticalSection(&m_clientsCriticalSection);
	if (!clientsEmpty) {
		m_apiCtrl.scanCtrlWin();
	}
	listClients();
	return client;
}
//////////////////////////////////////////////////////////////////////////							api ctrl events
// api ctrl events
void ClientsManager::attachApiAvailable(SkypeAPICtrl* apiCtrl) {
	m_apiCtrl.scanCtrlWin();
}

void ClientsManager::attachApiRefused(SkypeAPICtrl* apiCtrl) {
}

void ClientsManager::attachApiNotAvailable(SkypeAPICtrl* apiCtrl) {
}

void ClientsManager::attachApiAuthPending(SkypeAPICtrl* apiCtrl) {
}

void ClientsManager::attachApiSuccess(SkypeAPICtrl* apiCtrl, HWND ctrlWin) {
	SkypeClient* client = findClientbyWin(ctrlWin);
	if (client) {
		client->attached(ctrlWin);
	}
}

void ClientsManager::attachApiMessage(SkypeAPICtrl* apiCtrl, HWND ctrlWin,
		PCOPYDATASTRUCT msgData) {
	SkypeClient* client = findClientbyWin(ctrlWin);
	if (client) {
		if (msgData->dwData == 0) {
			string msg((char*) msgData->lpData, msgData->cbData);
			client->processMessage(msg);
		}
	}
}
